#import <Foundation/Foundation.h>
#import <Foundation/NSProcessInfo.h>
#import <AppKit/AppKit.h>

#include <QApplication>
#include <QWindow>
#include <QMenu>
#include <QMenuBar>
#include <QLabel>

#include <QDebug>

#include "MacAppHelper.h"

@interface HPObserver : NSObject<NSUserNotificationCenterDelegate>
                        - (id) init;
- (void) dealloc;
- (void) applicationDidFinishLaunching: (NSNotification *)aNotification;
@end

@implementation HPObserver
- (id) init
{
    if (self = [super init]) {
        //        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
        //        [nc addObserver:self
        //                        selector:@selector(applicationDidFinishLaunching:)
        //          name: NSApplicationDidFinishLaunchingNotification
        //          object: NSApp];
    }
    return self;
}

- (void) dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}

- (void) applicationDidFinishLaunching:(NSNotification *)aNotification
{
    @autoreleasepool {
        //        NSUserNotification *notification = [[aNotification userInfo] objectForKey:NSApplicationLaunchUserNotificationKey];
        //        if (notification.activationType == NSUserNotificationActivationTypeActionButtonClicked) {
        //        }
    }
}

- (void)userNotificationCenter:(NSUserNotificationCenter *)center
  didDeliverNotification:(NSUserNotification *)notification
{
    NSLog(@"recv notify");
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
                       BOOL notificationStillPresent;
                       do {
                           notificationStillPresent = NO;
                           for (NSUserNotification *nox in [[NSUserNotificationCenter defaultUserNotificationCenter] deliveredNotifications]){
                               if ([nox.identifier isEqualToString:notification.identifier]) notificationStillPresent = YES;
                           }
                           if (notificationStillPresent) [NSThread sleepForTimeInterval:0.20f];
                       } while (notificationStillPresent);
                       dispatch_async(dispatch_get_main_queue(),^{
                           //                           [self notificationHandlerForNotification:notification];
                       });
                   });
    NSLog(@"收到通知");

}

//用户已经点击了通知
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
    NSLog(@"user click");
    //    NSDictionary *dict = notification.userInfo;
    //    if (!dict)
    //        return;

    //    if (notification.activationType == NSUserNotificationActivationTypeContentsClicked) {
    //    } else {
    //        if ([notification.actionButtonTitle isEqualToString:@"关闭"]) { // 交易按钮

    //            [[NSUserNotificationCenter defaultUserNotificationCenter] removeAllDeliveredNotifications];
    //        }
    //    }

    //    if (notification.activationType == NSUserNotificationActivationTypeContentsClicked) { // 点击content
    //    } else { // 点击按钮
    //        if ([notification.actionButtonTitle isEqualToString:@"交易"]) { // 交易按钮
    //            if ([notification respondsToSelector:@selector(_alternateActionIndex)]) {
    //                NSNumber *alternateActionIndex = [(NSObject *)notification valueForKey:@"_alternateActionIndex"];
    //                NSInteger index = [alternateActionIndex integerValue];
    //                if (index > 2)
    //                    return;

    //                if (index != 0 && index != 1)
    //                    return;
    //            }
    //        }
    //    }

}

//returen YES;强制显示(即不管通知是否过多)
- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification
{
    return YES;
}
@end

HPObserver *serve = nil;

MacAppHelper::MacAppHelper()
{

}

// for mac [App Nap] result to QTimer not exactly
void MacAppHelper::disable_app_nap()
{
    if ([[NSProcessInfo processInfo] respondsToSelector:@selector(beginActivityWithOptions:reason:)])
    {
        [[NSProcessInfo processInfo] beginActivityWithOptions:0x00FFFFFF reason:@"Not sleepy and don't want to nap"];
    }
}

void MacAppHelper::installMenuAction(QApplication &app)
{
#ifdef USE_CEF
#else
    return;
#endif
    QMenuBar *m = new QMenuBar(0);
    QMenu *menu = m->addMenu(QObject::tr("Edit") );

    QAction *undoAction = new QAction(/*QObject::tr*/("Undo"));
    undoAction->setShortcut(QKeySequence("Ctrl+Z"));
    menu->addAction(undoAction);

    QAction *redoAction = new QAction(/*QObject::tr*/("Redo"));
    redoAction->setShortcut(QKeySequence("Shift+Ctrl+Z"));
    menu->addAction(redoAction);

    menu->addSeparator();

    QAction *deleteAction = new QAction(/*QObject::tr*/("Delete"));
    deleteAction->setShortcut(QKeySequence("Ctrl+D"));
    menu->addAction(deleteAction);

    QAction *cutAllAction = new QAction(/*QObject::tr*/("Cut"));
    cutAllAction->setShortcut(QKeySequence("Ctrl+X"));
    menu->addAction(cutAllAction);

    QAction *cpAction = new QAction(/*QObject::tr*/("Copy"));
    cpAction->setShortcut(QKeySequence("Ctrl+C"));
    menu->addAction(cpAction);

    QAction *pasteAction = new QAction(/*QObject::tr*/("Paste"));
    pasteAction->setShortcut(QKeySequence("Ctrl+V"));
    menu->addAction( pasteAction );

    menu->addSeparator();

    QAction *hideWindowAction = new QAction(/*QObject::tr*/("Hide"));
    hideWindowAction->setShortcut(QKeySequence("Ctrl+W"));
    menu->addAction(hideWindowAction);
    QObject::connect(hideWindowAction,&QAction::triggered,[](){
        // 对isActiveWindow进行判断
    });

    QAction *selectAllAction = new QAction(/*QObject::tr*/("Select All"));
    selectAllAction->setShortcut(QKeySequence("Ctrl+A"));
    menu->addAction(selectAllAction);
}

void MacAppHelper::postNotification(QString title, QString message)
{
    NSUserNotification* notification = [[NSUserNotification alloc] init];
    notification.title = title.toNSString();
    notification.subtitle = @"OK";
    notification.informativeText = message.toNSString();
    notification.soundName = NSUserNotificationDefaultSoundName;   //Will play a default sound
    //    notification.userInfo = ;

    [notification setValue:@YES forKey:@"_showsButtons"];
    notification.hasActionButton = YES;
    NSDictionary *dict = @{};
    notification.userInfo = dict;

    notification.actionButtonTitle = @"打开";
    notification.otherButtonTitle = @"关闭";

    //    [notification setHasActionButton: YES];
    //    [notification setActionButtonTitle: @"Action Button"];
    //    notification.userInfo = @{@"button":@"action"};
    //    [notification setOtherButtonTitle: @"Other Button"];

    //    [notification setDeliveryDate: [NSDate dateWithTimeIntervalSinceNow: 10]];

    //    [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:delegate];
    //    if (!serve) {
    qDebug() << "alloc delegate";
    serve = [[HPObserver alloc] init];
    //        [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:serve];
    //    }

    //    [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification: notification];

    //    [center scheduleNotification:userNotification];
    NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
    center.delegate = serve;
    [center scheduleNotification:notification];
    [notification autorelease];
}

void MacAppHelper::postNotification(QString title, QString subtitle, QString message)
{
    NSUserNotification* notification = [[NSUserNotification alloc] init];
    notification.title = title.toNSString();
    notification.subtitle = subtitle.toNSString();
    notification.informativeText = message.toNSString();
    notification.soundName = NSUserNotificationDefaultSoundName;   //Will play a default sound
    [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification: notification];
    [notification autorelease];
}

void MacAppHelper::setAppIconNumber(int num)
{
    if (num > 0) {
        [[[NSApplication sharedApplication] dockTile] setBadgeLabel:QString::number(num).toNSString()];
    } else if (num < 0) {
        [[[NSApplication sharedApplication] dockTile] setBadgeLabel:@""];
    } else {
        [[[NSApplication sharedApplication] dockTile] setBadgeLabel:@""];
    }
}

bool MacAppHelper::get_auto_start()
{
    NSURL *itemURL = [[NSBundle mainBundle] bundleURL];
    CFURLRef URLToToggle = (__bridge CFURLRef)itemURL;

    bool found = false;

    LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
    if (loginItems) {
        UInt32 seed = 0U;
        CFArrayRef currentLoginItems = LSSharedFileListCopySnapshot(loginItems,
                                                                    &seed);
        const CFIndex count = CFArrayGetCount(currentLoginItems);
        for (CFIndex idx = 0; idx < count; ++idx) {
            LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(currentLoginItems, idx);
            CFURLRef outURL = NULL;

            const UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)
            outURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, /*outError*/ NULL);
            if (outURL == NULL) {
#else
            OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &outURL, /*outRef*/ NULL);
            if (err != noErr || outURL == NULL) {
#endif
                if (outURL)
                    CFRelease(outURL);
                continue;
            }
            found = CFEqual(outURL, URLToToggle);
            CFRelease(outURL);

            if (found)
                break;
        }
        CFRelease(currentLoginItems);
        CFRelease(loginItems);
    }
    return found;
}

void MacAppHelper::set_auto_start(const QString &appname,bool enabled)
{
    NSURL *itemURL = [[NSBundle mainBundle] bundleURL];
    CFURLRef URLToToggle = (__bridge CFURLRef)itemURL;

    LSSharedFileListRef loginItems = LSSharedFileListCreate(kCFAllocatorDefault, kLSSharedFileListSessionLoginItems, /*options*/ NULL);
    if (loginItems) {
        UInt32 seed = 0U;
        Boolean found;
        LSSharedFileListItemRef existingItem = NULL;

        CFArrayRef currentLoginItems = LSSharedFileListCopySnapshot(loginItems,
                                                                    &seed);
        const CFIndex count = CFArrayGetCount(currentLoginItems);
        for (CFIndex idx = 0; idx < count; ++idx) {
            LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(currentLoginItems, idx);
            CFURLRef outURL = NULL;

            const UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)
            outURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, /*outError*/ NULL);
            if (outURL == NULL) {
#else
            OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &outURL, /*outRef*/ NULL);
            if (err != noErr || outURL == NULL) {
#endif
                if (outURL)
                    CFRelease(outURL);
                continue;
            }
            found = CFEqual(outURL, URLToToggle);
            CFRelease(outURL);

            if (found) {
                existingItem = item;
                break;
            }
        }

        if (enabled && !found) {
            NSString *displayName = appname.toNSString();
            IconRef icon = NULL;
            FSRef ref;
            // TODO: replace the deprecated CFURLGetFSRef
            Boolean gotRef = CFURLGetFSRef(URLToToggle, &ref);
            if (gotRef) {
                OSStatus err = GetIconRefFromFileInfo(
                            &ref,
                            /*fileNameLength*/ 0,
                            /*fileName*/ NULL, kFSCatInfoNone,
                            /*catalogInfo*/ NULL, kIconServicesNormalUsageFlag, &icon,
                            /*outLabel*/ NULL);
                if (err != noErr) {
                    if (icon)
                        CFRelease(icon);
                    icon = NULL;
                }
            }

            LSSharedFileListItemRef newItem = LSSharedFileListInsertItemURL(
                        loginItems, kLSSharedFileListItemBeforeFirst,
                        (__bridge CFStringRef)displayName, icon, URLToToggle,
                        /*propertiesToSet*/ NULL, /*propertiesToClear*/ NULL);
            if (newItem)
                CFRelease(newItem);
            if (icon)
                CFRelease(icon);
        } else if (!enabled && found) {
            LSSharedFileListItemRemove(loginItems, existingItem);
        }

        CFRelease(currentLoginItems);
        CFRelease(loginItems);
    }
}

MacAppHelper &MacAppHelper::get()
{
    static MacAppHelper instance;
    return instance;
}

void MacAppHelper::setMenuBar()
{
#define DEFAULT_W 20
#define DEFAULT_H 22
    NSTextField* txt      = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, DEFAULT_W, DEFAULT_H)];
    txt.editable = NO;
    txt.backgroundColor = [NSColor redColor];
    txt.stringValue = @"Hellow world!";

    NSView* mStatusBackgroundView = [[NSView alloc]initWithFrame:NSMakeRect(0, 0, DEFAULT_W, DEFAULT_H)];
    [mStatusBackgroundView addSubview:txt];

    NSStatusItem *mStatusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:DEFAULT_W];
    //    QLabel *label = new QLabel;
    //    label->setText("12");
    //    label->resize(DEFAULT_W,DEFAULT_H);
    mStatusItem.view = txt;
    //    mStatusItem.view = (NSView*)label->winId();
}

void MacAppHelper::toTop(QWindow *w, QScreen *s)
{
    NSView *view = reinterpret_cast<NSView*>(w->winId());

    //    [view.window setStyleMask: NSFullScreenWindowMask];
    [view.window setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces];//默认
    //    [view.window setMovableByWindowBackground:NO];
    //    [view.window setExcludedFromWindowsMenu:YES];
    //    [view.window setAlphaValue:1.0];
    //    [view.window setOpaque:NO];
    //    [view.window setHasShadow:NO];
    //    [view.window setHidesOnDeactivate:NO];
    //    [view.window setLevel:kCGBaseWindowLevel];
}

void MacAppHelper::toNormal(QWindow *w)
{
    NSView *view = reinterpret_cast<NSView*>(w->winId());
    if (view) {
        [view.window setStyleMask:15];
        [view.window setCollectionBehavior:128];
        [view.window setLevel:kCGMinimumWindowLevel];
    }
}

extern "C" void MacAppHelper::changeTitleBarColor(WId winId, double red, double green, double blue)
{
    if (winId == 0) {
        qDebug() << "winid 0";
        return;
    }
    NSView* view = (NSView*)winId;
    NSWindow* window = [view window];
    window.titlebarAppearsTransparent = YES;
    window.backgroundColor = [NSColor colorWithRed:red green:green blue:blue alpha:1.];
}

void MacAppHelper::hideMinMaxButton(WId winId)
{
    if (winId == 0) {
        qDebug() << "winid 0";
        return;
    }
    NSView* view = (NSView*)winId;
    NSWindow* window = [view window];
    [[window standardWindowButton:NSWindowZoomButton] setHidden:YES];
    [[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
}

bool MacAppHelper::isDarkMode() {
    if (@available(macOS 10.14, *)) {
        NSAppearance *apperance = NSApp.effectiveAppearance;
        return  [apperance bestMatchFromAppearancesWithNames:@[NSAppearanceNameDarkAqua,NSAppearanceNameAqua]] == NSAppearanceNameDarkAqua;
    } else {
        return YES;
    }
    return NO;
}
